/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-11-26
 * Time: 23:39
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;

using tools;

namespace Labb4.Entity
{
	/// <summary>
	/// Manages entities; adds, removes, and updates all entities.
	/// 
	/// This class is a manager, and needs to be initialized with a call to "Initialize"
	/// before the method Update can be successfully called.
	/// 
	/// This class is also implemented as a singleton.
	/// </summary>
	public sealed class EntityManager : Manager
	{
		#region members
		
		/// <summary>
		/// A reference to the one instance of this class.
		/// </summary>
		private static EntityManager		m_Instance = new EntityManager();
		/// <summary>
		/// References to all the entities
		/// </summary>
		private List<BasicEntity>			m_Entities;
		/// <summary>
		/// The local time
		/// </summary>
		private int							m_Counter;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members
		/// </summary>
		private EntityManager() :
			base()
		{
			m_Entities = new List<BasicEntity>();
			m_Counter = 0;
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Adds a reference to an entity
		/// </summary>
		/// <param name="entity"></param>
		public void AddEntity(BasicEntity entity)
		{
			m_Entities.Add(entity);
		}
		
		/// <summary>
		/// Gets the direction between an entity and a point. Unit is (radians)
		/// </summary>
		/// <param name="entity">The entity to start from</param>
		/// <param name="destX">The x coordinate to look for an angle for</param>
		/// <param name="destY">The y coordinate to look for an angle for</param>
		/// <returns>The direction from the entity's upper left corner handle, to the point (x, y). Unit is (radians)</returns>
		public float GetDirection(BasicEntity entity, ref float destX, ref float destY)
		{
			float direction = 0.0f;
			
			float startX = entity.Xpos;
			float startY = entity.Ypos;
			
			float deltaX = destX - startX;
			float deltaY = destY - startY;
			
			if(deltaY == 0.0f)
			{
				if(destX < startX)
				{
					direction = (float)Math.PI;
				}
			}
			else
			{
				if(deltaX == 0.0f)
				{
					if(destY < startY)
					{
						direction = (float)Math.PI * 1.5f;
					}
					
					if(destY > startY)
					{
						direction = (float)Math.PI * 0.5f;
					}
				}
				else
				{
					direction = (float)Math.Atan((double)(deltaY / deltaX));
					
					if(destX < startX)
					{
						direction -= (float)Math.PI;
					}
				}
			}
			
			while(direction < 0.0f)
			{
				direction += ((float)Math.PI * 2.0f);
			}
			
			while(direction > ((float)Math.PI * 2.0f))
			{
				direction -= ((float)Math.PI * 2.0f);
			}
			
			return direction;
		}
		
		/// <summary>
		/// Gets the distance between an entity and the point (x, y)
		/// </summary>
		/// <param name="entity">The entity to start from</param>
		/// <param name="destX">The x coordinate to look for the distance to</param>
		/// <param name="destY">The y coordinate to look for the distance to</param>
		/// <returns></returns>
		public float GetDistance(BasicEntity entity, ref float destX, ref float destY)
		{
			float distance = 0.0f;
			
			float startX = entity.Xpos;
			float startY = entity.Ypos;
			
			float deltaX = startX - destX;
			float deltaY = startY - destY;
			
			distance = (float)Math.Sqrt(Math.Pow((double)deltaX, 2.0) + Math.Pow((double)deltaY, 2.0));
			
			return distance;
		}
		
		/// <summary>
		/// Removes all the references to entities
		/// </summary>
		public void Clear()
		{
			m_Entities.Clear();
			m_Counter = 0;
		}
		
		#endregion
		
		#region overrides
		
		/// <summary>
		/// Updates all the enities, and removes those that are marked as dead.
		/// </summary>
		/// <param name="deltaTime"></param>
		protected override void DoUpdate(ref int deltaTime)
		{
			m_Counter += deltaTime;
			
			foreach(BasicEntity it in m_Entities)
			{
				it.Update(ref deltaTime);
				it.Draw();
			}
			
			bool grimReaperReaps = true;
			BasicEntity timeHasCome = null;
			
			while(grimReaperReaps)
			{
				foreach(BasicEntity it in m_Entities)
				{
					if(it.TimeToDie > 0)
					{
						if(it.TimeToDie < m_Counter)
						{
							timeHasCome = it;
						}
					}
				}
				
				if(timeHasCome != null)
				{
					m_Entities.Remove(timeHasCome);
					timeHasCome = null;
				}
				else
				{
					grimReaperReaps = false;
				}
			}
		}
		
		#endregion
		
		#region properties
		
		/// <summary>
		/// The one instance of this class (get)
		/// </summary>
		public static EntityManager Instance
		{
			get
			{
				return m_Instance;
			}
		}
		
		/// <summary>
		/// Local time (get)
		/// </summary>
		public int CurrentTime
		{
			get
			{
				return m_Counter;
			}
		}
		
		#endregion
	}
}
